package c09泛型;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

//泛型可以是任何合法单词
public class GenericTest<T> {
	protected Class<T> cls;

	T t;

	public GenericTest() {//注意构造器还是Simple()！而不是Simple<T>()！
		System.err.println("构造器");
	}

	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}

	public static void main(String[] args) {
		GenericTest s = new GenericTest();//即使Simple带有泛型，但是使用时没有强制要求指明类型！
		GenericTest<String> st = new GenericTest<String>();
		//可以认为Simple<String>是Simple的一个子类，但是实际上并不存在这样的类型！
		System.err.println(s.getClass() == st.getClass());//true！说明并没有把它们当作两种不同类型来处理！
		//对于Java来说，它认为两者类型相同，所以如下正确：
		s = st;
		st = s;

		SubGenericTest0<String> sgt = new SubGenericTest0<>();
	}

}

//继承时还是可以使用相同的泛型T！与疯狂Java讲义不同！但是子类也要加上泛型声明，否则如下注释行是错的：
//class SubGenericTest extends GenericTest<T>{}
//经过测试发现，如果把T改成任何字母都可以，只要保持与extends后面的泛型相同即可：
class SubGenericTest0<T> extends GenericTest<T> {//SubGenericTest0后必须加上<T>！
	T t2;

	public SubGenericTest0() {
		t2 = t;//赋值完全没错！说明这里的T与父类的T是相同类型！
		Type genType = getClass().getGenericSuperclass();
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		cls = (Class) params[0];
		System.err.println(cls.getName());
	}

	public T getT2() {
		return t2;
	}

	public void setT2(T t2) {
		this.t2 = t2;
	}
}

//继承时也可以直接指定T的类型，这是子类后面就不用加上<String>了！相应的，T也就被替换成了String！
class SubGenericTest2 extends GenericTest<String> {
}

//这样也可以，但是不推荐！
class SubGenericTest3 extends GenericTest {
}
